﻿using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Tmds.DBus.Protocol;
using Ursa.Controls;

namespace DaqConfigureTool.ViewModels
{
    public enum ChannelType
    {
        Voltage,
        Current,
        Resistance,
        Temperature,
        Humidity,
        Pressure,

        NTC,
        KThermoCouple,
        JThermoCouple,
        TThermoCouple,
        UserDefine,
    }
    public partial class ChannelInfo : ObservableObject
    {

    }

    public partial class SlotInfoModel : ObservableObject
    {
        [JsonIgnore]
        public static List<string> AvailableTypes => ["电压", "电流", "NTC"];

        private string type = "V";
        [JsonPropertyName("type")]
        public string Type
        {
            get { return type; }
            set
            {
                SetProperty(ref type, value);
            }
        }

        private bool isEnabled;
        [JsonPropertyName("isEnabled")]
        public bool IsEnabled
        {
            get { return isEnabled; }
            set { SetProperty(ref isEnabled, value); }
        }
    }

    public class SlotsResult
    {
        [JsonPropertyName("slots")]
        public SlotInfoModel[]? Slots { get; set; }
    }

    public partial class MainViewModel : ObservableObject
    {
       
        [ObservableProperty]
        [NotifyCanExecuteChangedFor(nameof(SetSNCommand))]
        private string? sN;
        [ObservableProperty]
        private string? fwVersion;
        [ObservableProperty]
        private DX2100 dx2100 = new DX2100();
        [ObservableProperty]
        [NotifyCanExecuteChangedFor(nameof(SaveSlotSettingsCommand))]
        private ObservableCollection<SlotInfoModel>? slots;


        private readonly string cfgPath = "./ip.cfg";

        public MainViewModel()
        {
            if (!File.Exists(cfgPath))
            {
                File.WriteAllText(cfgPath, "192.168.32.52");
            }
            string ip = File.ReadAllText(cfgPath);
            Dx2100.Address = IPAddress.Parse(ip);
        }

        [RelayCommand]
        private async Task GetDeviceInfo()
        {
            if(Dx2100.Address == null)
            {
                var result = await MessageBox.ShowOverlayAsync("地址无效", "错误", "", icon:MessageBoxIcon.Error, MessageBoxButton.OK);
                return;
            }
            await Task.Run(() =>
            {
                File.WriteAllText(cfgPath, Dx2100.Address.ToString());
            });
            await Dx2100.GetChannelsAsync(CancellationToken.None);
            //await GetSlotInfo();
        }

        private bool CanSetSN()
        {
            if (string.IsNullOrWhiteSpace(SN)) return false;
            return SN.Length >= 1;
        }
        [RelayCommand(CanExecute = nameof(CanSetSN))]
        private async Task SetSN()
        {
            await Dx2100.SetSN(SN, CancellationToken.None);
            await GetDeviceInfo();
        }
        [RelayCommand]
        private async Task SetTime()
        {
            await Dx2100.SetTime(CancellationToken.None);
        }

        private bool buzzerState = false;
        [RelayCommand]
        private async Task SetBuzzer()
        {
            buzzerState = !buzzerState;
            await Dx2100.SetBuzzer(buzzerState, CancellationToken.None);
        }

        [RelayCommand]
        private async Task GetSlotInfo()
        {
            await Dx2100.SendRpcRequest("get_slot_info", null, 0, CancellationToken.None);
            var response = await Dx2100.ReceiveRpcResponse(CancellationToken.None);
            var result = response.Result.ToString();
            if (string.IsNullOrWhiteSpace(result))
            {
                return;
            }
            var slotsResult = JsonSerializer.Deserialize<SlotsResult>(result);
            if (slotsResult != null && slotsResult.Slots != null)
            {
                Slots = new ObservableCollection<SlotInfoModel>(slotsResult.Slots);
            }
        }


        [ObservableProperty]
        private double calibrationOhm;

        [ObservableProperty]
        private double calibrationMOhm;

        [ObservableProperty]
        private double setCalibrationOhm;

        [ObservableProperty]
        private double setCalibrationMOhm;

        [RelayCommand]
        private async Task GetCalibration()
        {
            await Dx2100.SendRpcRequest("get_daq_cal_param", null, 0, CancellationToken.None);
            var response = await Dx2100.ReceiveRpcResponse(CancellationToken.None);
            var result = response.Result.ToString();
            if (string.IsNullOrWhiteSpace(result))
            {
                return;
            }
            var sArray = result.Split(',');
            if(sArray.Count() != 2)
            {
                return;
            }
            CalibrationOhm = double.Parse(sArray[0]) / 1000000;
            CalibrationMOhm = double.Parse(sArray[1]) / 1000000;
        }

        [RelayCommand]
        private async Task SetCalibration()
        {
            await Dx2100.SendRpcRequest("set_daq_cal_param", new double[] { SetCalibrationOhm, SetCalibrationMOhm }, 0, CancellationToken.None);
            var response = await Dx2100.ReceiveRpcResponse(CancellationToken.None);
            await GetCalibration();
        }


        private bool CanSaveSlotSettings()
        {
            return Slots != null && Slots.Count > 0;
        }

        [RelayCommand(CanExecute = nameof(CanSaveSlotSettings))]
        private async Task SaveSlotSettings()
        {
            if (Slots == null || Slots.Count == 0) return;
            var slotsResult = new SlotsResult();
            slotsResult.Slots = Slots.ToArray();
            string text = JsonSerializer.Serialize(slotsResult);
            await Dx2100.SendRpcRequest("set_slot_info", new string[] { text }, 0, CancellationToken.None);
            var response = await Dx2100.ReceiveRpcResponse(CancellationToken.None);
        }
    }
}
